#!/bin/bash

set -e

# 显示用法
show_usage() {
    cat << EOF
通用应用程序打包工具（支持跨架构）

用法: $0 [选项] <应用程序路径>

选项:
  -n, --name NAME        指定应用程序名称 (默认: 从文件名推断)
  -c, --config FILE      使用配置文件
  -s, --search PATH      添加库搜索路径 (可多次使用)
  -o, --output DIR       输出目录 (默认: ./deployments)
  -p, --plugins DIR      QT插件目录
  -a, --arch ARCH        指定目标架构 (auto|x86_64|aarch64|armhf)
  --no-qt                不打包QT库和插件
  --sys-libs             打包系统库 (谨慎使用)
  -h, --help            显示此帮助信息

支持的架构:
  x86_64    - 64位x86架构
  aarch64   - 64位ARM架构
  armhf     - 32位ARM硬浮点架构
  auto      - 自动检测 (默认)

示例:
  $0 /path/to/myapp
  $0 -n MyApp -s /opt/custom/lib /build/myapp
  $0 -c myconfig.conf /build/myapp
  $0 -a aarch64 /build/arm-app
EOF
}

# 解析命令行参数
APP_PATH=""
APP_NAME=""
CONFIG_FILE=""
SEARCH_PATHS=""
QT_PLUGINS=""
OUTPUT_DIR="./deployments"
PACKAGE_QT="true"
PACKAGE_SYS_LIBS="false"
TARGET_ARCH="auto"

while [ $# -gt 0 ]; do
    case $1 in
        -n|--name)
            APP_NAME="$2"
            shift 2
            ;;
        -c|--config)
            CONFIG_FILE="$2"
            shift 2
            ;;
        -s|--search)
            if [ -z "$SEARCH_PATHS" ]; then
                SEARCH_PATHS="$2"
            else
                SEARCH_PATHS="$SEARCH_PATHS:$2"
            fi
            shift 2
            ;;
        -o|--output)
            OUTPUT_DIR="$2"
            shift 2
            ;;
        -p|--plugins)
            QT_PLUGINS="$2"
            shift 2
            ;;
        -a|--arch)
            TARGET_ARCH="$2"
            shift 2
            ;;
        --no-qt)
            PACKAGE_QT="false"
            shift
            ;;
        --sys-libs)
            PACKAGE_SYS_LIBS="true"
            shift
            ;;
        -h|--help)
            show_usage
            exit 0
            ;;
        -*)
            echo "未知选项: $1"
            show_usage
            exit 1
            ;;
        *)
            APP_PATH="$1"
            shift
            ;;
    esac
done

# 验证应用程序路径
if [ -z "$APP_PATH" ]; then
    echo "错误: 必须指定应用程序路径"
    show_usage
    exit 1
fi

if [ ! -f "$APP_PATH" ]; then
    echo "错误: 应用程序不存在: $APP_PATH"
    exit 1
fi

# 加载配置文件
if [ -n "$CONFIG_FILE" ] && [ -f "$CONFIG_FILE" ]; then
    echo "使用配置文件: $CONFIG_FILE"
    # 安全地加载配置
    while IFS='=' read -r key value; do
        # 跳过空行和注释
        if echo "$key" | grep -q "^[[:space:]]*#"; then
            continue
        fi
        if [ -z "$key" ]; then
            continue
        fi
        
        # 移除前后的空格
        key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
        value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
        
        case "$key" in
            APP_NAME)
                APP_NAME="$value"
                ;;
            SEARCH_PATHS)
                SEARCH_PATHS="$value"
                ;;
            QT_PLUGINS)
                QT_PLUGINS="$value"
                ;;
            OUTPUT_DIR)
                OUTPUT_DIR="$value"
                ;;
            TARGET_ARCH)
                TARGET_ARCH="$value"
                ;;
        esac
    done < "$CONFIG_FILE"
fi

# 检测目标架构
detect_architecture() {
    local binary="$1"
    local file_info
    file_info=$(file "$binary")
    
    if echo "$file_info" | grep -q "ARM aarch64"; then
        echo "aarch64"
    elif echo "$file_info" | grep -q "ARM, EABI5" | grep -q "hard-float"; then
        echo "armhf"
    elif echo "$file_info" | grep -q "x86-64"; then
        echo "x86_64"
    elif echo "$file_info" | grep -q "Intel 80386"; then
        echo "i386"
    else
        echo "unknown"
    fi
}

# 设置应用程序名称
if [ -z "$APP_NAME" ]; then
    APP_NAME=$(basename "$APP_PATH")
    echo "自动推断应用程序名称: $APP_NAME"
fi

# 自动检测架构
if [ "$TARGET_ARCH" = "auto" ]; then
    TARGET_ARCH=$(detect_architecture "$APP_PATH")
    echo "自动检测目标架构: $TARGET_ARCH"
fi

# 根据架构设置默认搜索路径
setup_architecture_paths() {
    local arch="$1"
    
    case "$arch" in
        "aarch64")
            DEFAULT_SEARCH_PATHS="/usr/lib/aarch64-linux-gnu:/usr/local/lib/aarch64-linux-gnu:/opt/qt/qt5.15.3-arm-old/lib:/usr/local/opencv-arm64/lib"
            ;;
        "armhf")
            DEFAULT_SEARCH_PATHS="/usr/lib/arm-linux-gnueabihf:/usr/local/lib/arm-linux-gnueabihf:/opt/qt/qt5.15.3-armhf/lib"
            ;;
        "x86_64")
            DEFAULT_SEARCH_PATHS="/usr/lib/x86_64-linux-gnu:/usr/local/lib:/usr/lib64"
            ;;
        *)
            DEFAULT_SEARCH_PATHS="/usr/lib:/usr/local/lib:/lib"
            ;;
    esac
    
    # 添加通用路径
    DEFAULT_SEARCH_PATHS="$DEFAULT_SEARCH_PATHS:/usr/lib:/usr/local/lib:/lib"
}

setup_architecture_paths "$TARGET_ARCH"

# 设置搜索路径
if [ -n "$SEARCH_PATHS" ]; then
    ALL_SEARCH_PATHS="$SEARCH_PATHS:$DEFAULT_SEARCH_PATHS"
else
    ALL_SEARCH_PATHS="$DEFAULT_SEARCH_PATHS"
fi

# 去重搜索路径
UNIQUE_SEARCH_PATHS=""
IFS_OLD="$IFS"
IFS=":"
for path in $ALL_SEARCH_PATHS; do
    if [ -d "$path" ]; then
        if echo "$UNIQUE_SEARCH_PATHS" | grep -q ":$path:" || [ "$UNIQUE_SEARCH_PATHS" = "$path" ]; then
            continue
        fi
        if [ -z "$UNIQUE_SEARCH_PATHS" ]; then
            UNIQUE_SEARCH_PATHS="$path"
        else
            UNIQUE_SEARCH_PATHS="$UNIQUE_SEARCH_PATHS:$path"
        fi
    fi
done
IFS="$IFS_OLD"

# 清理输出目录路径
OUTPUT_DIR=$(echo "$OUTPUT_DIR" | sed 's/^"//;s/"$//;s/^'"'"'//;s/'"'"'$//')

# 创建输出目录
DEPLOY_DIR="$OUTPUT_DIR/deploy_${APP_NAME}_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$DEPLOY_DIR/lib"
mkdir -p "$DEPLOY_DIR/plugins"
mkdir -p "$DEPLOY_DIR/config"
mkdir -p "$DEPLOY_DIR/bin"

echo "=== 通用应用程序打包（跨架构支持）==="
echo "应用程序: $APP_PATH"
echo "应用名称: $APP_NAME"
echo "目标架构: $TARGET_ARCH"
echo "输出目录: $DEPLOY_DIR"
echo "搜索路径: $UNIQUE_SEARCH_PATHS"
echo "打包QT: $PACKAGE_QT"
echo "打包系统库: $PACKAGE_SYS_LIBS"

# 复制应用程序
cp "$APP_PATH" "$DEPLOY_DIR/bin/$APP_NAME"
echo "✓ 复制应用程序: $APP_NAME"

# 查找库函数
# 在find_library函数中添加架构检查
find_library() {
    local lib_name="$1"
    
    # 首先在部署目录中查找（避免重复）
    if find "$DEPLOY_DIR/lib" -name "$lib_name" -type f 2>/dev/null | head -1 | grep -q .; then
        return 0
    fi
    
    # 在搜索路径中查找
    IFS=":"
    for path in $UNIQUE_SEARCH_PATHS; do
        if [ -d "$path" ]; then
            local found
            found=$(find "$path" -name "$lib_name" -type f 2>/dev/null | head -1)
            if [ -n "$found" ]; then
                # 检查库文件架构
                local lib_arch
                lib_arch=$(detect_architecture "$found" 2>/dev/null || echo "unknown")
                
                if [ "$lib_arch" = "$TARGET_ARCH" ] || [ "$lib_arch" = "unknown" ]; then
                    echo "✓ 找到: $lib_name -> $found"
                    cp "$found" "$DEPLOY_DIR/lib/" 2>/dev/null || true
                    # 同时复制相关的符号链接
                    local lib_base
                    lib_base=$(echo "$lib_name" | sed 's/\.so.*/.so/')
                    find "$path" -name "${lib_base}*" -type l -exec cp -P {} "$DEPLOY_DIR/lib/" \; 2>/dev/null || true
                    return 0
                else
                    echo "⚠ 跳过架构不匹配的库: $lib_name (架构: $lib_arch, 需要: $TARGET_ARCH)"
                    continue
                fi
            fi
        fi
    done
    IFS="$IFS_OLD"
    
    echo "⚠ 未找到: $lib_name"
    return 1
}

# 通用依赖分析（使用readelf）
analyze_dependencies_generic() {
    local binary="$1"
    
    echo "=== 使用readelf分析依赖关系 ==="
    
    local missing_count=0
    
    # 使用readelf读取动态段
    readelf -d "$binary" 2>/dev/null | grep "Shared library" | while read -r line; do
        local lib_name
        lib_name=$(echo "$line" | sed -n 's/.*\[\(.*\)\]/\1/p')
        if [ -n "$lib_name" ]; then
            echo "依赖: $lib_name"
            if ! find_library "$lib_name"; then
                missing_count=$((missing_count + 1))
            fi
        fi
    done
    
    return $missing_count
}

# ARM架构专用分析
analyze_arm_dependencies() {
    local binary="$1"
    
    echo "=== ARM架构依赖分析 ==="
    
    local missing_count=0
    
    # 方法1: 使用readelf（主要方法）
    analyze_dependencies_generic "$binary"
    missing_count=$?
    
    # 方法2: 尝试使用QEMU（如果可用）
    if command -v qemu-aarch64 >/dev/null 2>&1 && [ "$TARGET_ARCH" = "aarch64" ]; then
        echo "=== 使用QEMU辅助分析 ==="
        if qemu-aarch64 -L /usr/aarch64-linux-gnu ldd "$binary" 2>/dev/null; then
            qemu-aarch64 -L /usr/aarch64-linux-gnu ldd "$binary" 2>/dev/null | while IFS= read -r line; do
                if echo "$line" | grep -q "=>"; then
                    local lib_path
                    lib_path=$(echo "$line" | awk '{print $3}')
                    local lib_name
                    lib_name=$(basename "$lib_path" 2>/dev/null)
                    
                    if [ -n "$lib_name" ] && [ "$lib_name" != "not" ]; then
                        echo "QEMU分析: $lib_name"
                        find_library "$lib_name"
                    fi
                fi
            done
        fi
    fi
    
    return $missing_count
}

# 主依赖分析函数
analyze_dependencies() {
    local binary="$1"
    local arch="$2"
    
    case "$arch" in
        "aarch64"|"armhf")
            analyze_arm_dependencies "$binary"
            ;;
        *)
            analyze_dependencies_generic "$binary"
            ;;
    esac
}

# 打包QT库和插件
# 在package_qt函数中修改插件复制逻辑
package_qt() {
    if [ "$PACKAGE_QT" != "true" ]; then
        return 0
    fi
    
    echo "=== 打包QT组件 ==="
    
    # 自动检测QT库路径
    if [ -z "$QT_PLUGINS" ]; then
        IFS=":"
        for path in $UNIQUE_SEARCH_PATHS; do
            local potential_plugins
            potential_plugins=$(dirname "$path")/plugins
            if [ -d "$potential_plugins" ] && [ "$(detect_architecture "$path/libQt5Core.so.5" 2>/dev/null || echo "unknown")" = "$TARGET_ARCH" ]; then
                QT_PLUGINS="$potential_plugins"
                echo "自动发现QT插件目录: $QT_PLUGINS"
                break
            fi
        done
        IFS="$IFS_OLD"
    fi
    
    if [ -n "$QT_PLUGINS" ] && [ -d "$QT_PLUGINS" ]; then
        echo "复制QT插件: $QT_PLUGINS"
        mkdir -p "$DEPLOY_DIR/plugins"
        # 只复制与目标架构匹配的插件
        find "$QT_PLUGINS" -type f -name "*.so" | while read -r plugin; do
            local plugin_arch
            plugin_arch=$(detect_architecture "$plugin" 2>/dev/null || echo "unknown")
            if [ "$plugin_arch" = "$TARGET_ARCH" ] || [ "$plugin_arch" = "unknown" ]; then
                local rel_path
                rel_path=$(realpath --relative-to="$QT_PLUGINS" "$plugin")
                mkdir -p "$DEPLOY_DIR/plugins/$(dirname "$rel_path")"
                cp "$plugin" "$DEPLOY_DIR/plugins/$rel_path" 2>/dev/null || true
                echo "✓ 复制插件: $rel_path"
            else
                echo "⚠ 跳过架构不匹配的插件: $plugin (架构: $plugin_arch)"
            fi
        done
    else
        echo "警告: 未找到QT插件目录"
    fi
    
    # 复制常见的QT库
    echo "复制QT核心库..."
    local qt_libs="Core Gui Widgets Network Sql"
    for lib in $qt_libs; do
        find_library "libQt5${lib}.so*" || echo "⚠ 未找到QT库 libQt5${lib}.so"
    done
    
    # 特别处理平台插件 - 确保使用正确架构
    # 在package_qt函数中替换平台插件查找部分
    # 特别处理平台插件 - 确保使用正确架构
    echo "查找平台插件..."
   # 首先在ARM QT路径中查找
   local arm_qt_path="/opt/qt/qt5.15.3-arm-old"
   if [ -d "$arm_qt_path/plugins/platforms" ]; then
        find "$arm_qt_path/plugins/platforms" -name "*.so" | while read -r platform_plugin; do
            local plugin_arch
            plugin_arch=$(detect_architecture "$platform_plugin" 2>/dev/null || echo "unknown")
            if [ "$plugin_arch" = "$TARGET_ARCH" ]; then
                mkdir -p "$DEPLOY_DIR/plugins/platforms"
                cp "$platform_plugin" "$DEPLOY_DIR/plugins/platforms/"
                echo "✓ 复制ARM平台插件: $(basename "$platform_plugin")"
            fi
        done
    fi

    # 如果还没有找到平台插件，再尝试通用查找（但跳过架构不匹配的）
    if [ ! -f "$DEPLOY_DIR/plugins/platforms/libqxcb.so" ]; then
        find_library "libqxcb.so" 
        if [ $? -eq 0 ]; then
            # 检查复制的插件架构
            local copied_plugin="$DEPLOY_DIR/plugins/platforms/libqxcb.so"
            if [ -f "$copied_plugin" ]; then
                local plugin_arch
                plugin_arch=$(detect_architecture "$copied_plugin" 2>/dev/null || echo "unknown")
                if [ "$plugin_arch" != "$TARGET_ARCH" ]; then
                    echo "⚠ 删除架构不匹配的平台插件: $plugin_arch"
                    rm -f "$copied_plugin"
                fi
            fi
        fi
    fi
}

# 创建启动脚本
create_launch_scripts() {
    echo "=== 创建启动脚本 ==="
    
    # 主启动脚本
    cat > "$DEPLOY_DIR/run.sh" << EOF
#!/bin/bash
SCRIPT_DIR=\$(cd "\$(dirname "\$0")" && pwd)
export LD_LIBRARY_PATH="\${SCRIPT_DIR}/lib:\${LD_LIBRARY_PATH}"
export QT_QPA_PLATFORM_PLUGIN_PATH="\${SCRIPT_DIR}/plugins"
export QT_PLUGIN_PATH="\${SCRIPT_DIR}/plugins"
cd "\${SCRIPT_DIR}/bin"
echo "启动应用程序: $APP_NAME"
echo "架构: $TARGET_ARCH"
echo "库路径: \${SCRIPT_DIR}/lib"
exec "./$APP_NAME" "\$@"
EOF

    # 调试脚本
    cat > "$DEPLOY_DIR/debug.sh" << EOF
#!/bin/bash
echo "=== 部署环境检查 ==="
echo "目录: \$(pwd)"
echo "架构: $TARGET_ARCH"
echo ""
echo "文件结构:"
find . -type f -name "*.so" -o -name "*.sh" -o -name "$APP_NAME" | sort
echo ""
echo "库文件详情:"
find lib -name "*.so*" -exec file {} \; 2>/dev/null | head -20
echo ""
echo "应用程序信息:"
file "bin/$APP_NAME"
echo ""
echo "依赖检查:"
if command -v ldd >/dev/null 2>&1; then
    ldd "bin/$APP_NAME" 2>/dev/null || echo "无法用ldd分析（可能是跨架构）"
else
    echo "ldd命令不可用"
fi
EOF

    # 环境检查脚本
    cat > "$DEPLOY_DIR/check_env.sh" << EOF
#!/bin/bash
echo "=== 目标设备环境检查 ==="
echo "设备架构: \$(uname -m)"
echo "系统信息: \$(uname -a)"
echo "GLIBC版本: \$(ldd --version 2>/dev/null | head -1 || echo "未知")"
echo "库路径: \$LD_LIBRARY_PATH"
echo ""
echo "当前目录库文件:"
find . -name "*.so" -exec sh -c 'echo "  \$(basename {}) -> \$(file {})"' \; 2>/dev/null
EOF

    chmod +x "$DEPLOY_DIR/run.sh" "$DEPLOY_DIR/debug.sh" "$DEPLOY_DIR/check_env.sh"
    
    echo "✓ 启动脚本创建完成"
}

# 创建部署说明
create_deploy_readme() {
    cat > "$DEPLOY_DIR/README.md" << EOF
# $APP_NAME 部署包

## 应用信息
- 应用名称: $APP_NAME
- 目标架构: $TARGET_ARCH
- 打包时间: $(date)
- QT支持: $PACKAGE_QT

## 部署说明

1. **将整个目录复制到目标设备**
   \`\`\`bash
   scp -r $(basename "$DEPLOY_DIR") user@target-device:/path/to/deploy/
   \`\`\`

2. **在目标设备上运行**
   \`\`\`bash
   cd /path/to/deploy/$(basename "$DEPLOY_DIR")
   ./run.sh
   \`\`\`

3. **环境检查**
   \`\`\`bash
   ./check_env.sh    # 检查目标设备环境
   ./debug.sh        # 检查部署包内容
   \`\`\`

## 目录结构
\`\`\`
$(basename "$DEPLOY_DIR")/
├── bin/$APP_NAME          # 应用程序
├── lib/                   # 依赖库
├── plugins/               # QT插件
├── run.sh                 # 启动脚本
├── debug.sh               # 调试脚本
├── check_env.sh           # 环境检查
└── README.md             # 说明文档
\`\`\`

## 注意事项
- 确保目标设备具有相同的架构 ($TARGET_ARCH)
- 如果需要图形界面，确保目标设备有X11或Wayland支持
- 检查目标设备的GLIBC版本兼容性
EOF

    echo "✓ 部署说明创建完成"
}

# 主打包流程
echo ""
echo "开始分析依赖关系..."
if analyze_dependencies "$APP_PATH" "$TARGET_ARCH"; then
    echo "✓ 依赖分析完成"
else
    echo "⚠ 部分依赖库可能未找到，请检查上述警告"
fi

package_qt
create_launch_scripts
create_deploy_readme

# 创建压缩包
PACKAGE_FILE="$OUTPUT_DIR/${APP_NAME}_${TARGET_ARCH}_deploy_$(date +%Y%m%d_%H%M%S).tar.gz"
tar -czf "$PACKAGE_FILE" -C "$(dirname "$DEPLOY_DIR")" "$(basename "$DEPLOY_DIR")"

echo ""
echo "=== 打包完成 ==="
echo "部署目录: $DEPLOY_DIR"
echo "压缩包: $PACKAGE_FILE"
echo "文件大小: $(du -sh "$DEPLOY_DIR" | cut -f1)"
echo "目标架构: $TARGET_ARCH"
echo ""
echo "部署命令:"
echo "  tar -xzf $(basename "$PACKAGE_FILE")"
echo "  cd deploy_${APP_NAME}_*"
echo "  ./check_env.sh    # 首先检查目标环境"
echo "  ./run.sh          # 运行应用程序"
echo ""
echo "注意: 此包为 $TARGET_ARCH 架构，请在相同架构的设备上运行"
